from typing import Optional

import numpy as np
from scipy.stats import linregress

class SignalGenerator:
    def __init__(self, config: dict, positons: dict):
        self.ema_period = config.get('ema_period', 20)
        self.rsi_period = config.get('rsi_period', 14)
        self.adx_threshold = config.get('adx_threshold', 25)
        self.rsi_overbought = config.get('rsi_overbought', 70)
        self.rsi_oversold = config.get('rsi_oversold', 30)

        self.positions = positons

    def generate_signal(self, indicators: dict) -> Optional[str]:
        """
        新版信号生成接口
        参数:
            indicators: 包含预计算指标的字典
        返回:
            Optional[str]: 交易信号 (LONG, SHORT, CLOSE_LONG, CLOSE_SHORT)
        """
        # 指标有效性检查
        required_keys = {'ema', 'rsi', 'macd_hist', 'adx'}
        if not all(key in indicators for key in required_keys):
            return None

        try:
            return self._generate_core_signal(indicators)
        except Exception as e:
            print(f"信号生成异常: {str(e)}")
            return None

    def _generate_core_signal(self, indicators: dict) -> Optional[str]:
        # 从字典中提取标量值
        try:
            adx = float(indicators['adx'])
            rsi = float(indicators['rsi'])
            macd_hist = float(indicators['macd_hist'])
            ema = float(indicators['ema'])
        except (KeyError, TypeError) as e:
            print(f"指标数据缺失或类型错误: {str(e)}")
            return None

        # 趋势强度判断（使用标量）
        if adx > self.adx_threshold:
            # 强趋势逻辑
            if ema > indicators['close']:  # 假设close是历史序列
                if macd_hist > 0 and rsi < self.rsi_overbought:
                    return "LONG"
            else:
                if macd_hist < 0 and rsi > self.rsi_oversold:
                    return "SHORT"
        else:
            # 震荡市逻辑
            if rsi > self.rsi_overbought:
                return "CLOSE_LONG"
            elif rsi < self.rsi_oversold:
                return "CLOSE_SHORT"
        return None

    @classmethod
    def _calculate_macd_trend(cls, hist_values: np.ndarray) -> str:
        """判断MACD直方图趋势（改进版）"""
        # print(type(hist_values))

        # 输入验证
        if not isinstance(hist_values, np.ndarray):
            raise TypeError("hist_values 必须是 numpy 数组")
        if hist_values.size < 3:
            return "neutral"

        recent = hist_values[-3:]

        # 容差处理避免浮点误差
        tolerance = 1e-5
        all_positive = all(x > tolerance for x in recent)
        all_negative = all(x < -tolerance for x in recent)

        # 判断递增/递减
        increasing = all(x > y for x, y in zip(recent[1:], recent[:-1]))
        decreasing = all(x < y for x, y in zip(recent[1:], recent[:-1]))

        # 趋势判断
        if all_positive and increasing:
            return "bullish"
        elif all_negative and decreasing:
            return "bearish"
        else:
            # 附加趋势强度判断
            slope = cls._calculate_slope(recent)
            if slope > 0.1:
                return "bullish_weak"
            elif slope < -0.1:
                return "bearish_weak"
            return "neutral"

    def _calculate_slope(data: np.ndarray) -> float:
        """计算斜率"""
        x = np.arange(len(data))
        slope, _, _, _, _ = linregress(x, data)
        return slope

    def _handle_strong_trend(self, indicators: dict, macd_trend: str) -> Optional[str]:
        # 强趋势逻辑
        if indicators['ema'] > np.mean(indicators['close'][-5:]):
            if macd_trend == "bullish" and indicators['rsi'] < self.rsi_overbought:
                return "LONG"
        elif indicators['ema'] < np.mean(indicators['close'][-5:]):
            if macd_trend == "bearish" and indicators['rsi'] > self.rsi_oversold:
                return "SHORT"
        return None

    def _handle_weak_trend(self, indicators: dict, macd_trend: str) -> Optional[str]:
        # 震荡市逻辑
        if indicators['rsi'] > self.rsi_overbought:
            return "CLOSE_LONG" if macd_trend == "bearish" else None
        elif indicators['rsi'] < self.rsi_oversold:
            return "CLOSE_SHORT" if macd_trend == "bullish" else None
        return None